package ru.qrck.quitetaskmanager;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import android.app.ActivityManager;
import android.content.pm.PackageManager;
import android.os.Debug;
import android.util.Log;

public class ProcessUtils {
	
	private static final String TAG = "QTM.PU";

//	private PackageManager mPackageManager = null;
	private ActivityManager mActivityManager = null;
	private ProcessInfoTable mProcTable = null;
	
	public ProcessUtils(
						PackageManager pkg, 
						ActivityManager act,
						ProcessInfoTable ptable
						) 
	{
//		mPackageManager = pkg;
		mActivityManager = act;
		mProcTable = ptable;
	}
	
	private String getProcProcfsStatus(int pid) {

		String ret = "PID:\t\t" + pid + "\n";
		
		File fStatus = new File("/proc/" + pid + "/status");
		if(fStatus == null || !fStatus.isFile() || !fStatus.canRead()) {
			return ret;
		}
    	try {
    		FileInputStream fIn = new FileInputStream(fStatus);
    		InputStreamReader rIn = new InputStreamReader(fIn);
    		BufferedReader reader = new BufferedReader(rIn, 256);
    		String line = null;
    		while((line = reader.readLine()) != null) {
    			
    			//Log.v(TAG, "[" + line + "]");
    			
    			if(line.startsWith("Name:\t")) {    				
    				//ret += "Name: " + line.substring(line.lastIndexOf('\t') + 1) + "\n";    				
    			} else if(line.startsWith("State:\t")) {    				
    				ret += "State: \t" + line.substring(line.lastIndexOf('\t') + 1) + "\n";;    				
    			} else if(line.startsWith("PPid:\t")) {    				
    				ret += "PPID:\t\t" + new Integer(line.substring(line.lastIndexOf('\t') + 1)).intValue() + "\n";;    				
    			}  else if(line.startsWith("Threads:\t")) {    				
    				ret += "Threads: \t" + new Integer(line.substring(line.lastIndexOf('\t') + 1)).intValue() + "\n";;
    				// we need not read below.
    	    		reader.close();
    	    		rIn.close();
    	    		fIn.close();
    				break;
    			}     			
    		}
    		reader.close();
    		rIn.close();
    		fIn.close();
    	} catch(FileNotFoundException e) {
			Log.e("TAG", "FileNotFoundException", e);
    	} catch(IOException e) {
			Log.e("TAG", "IOException", e);
    	}
    	
    	return ret;
	}
	
    public String getProcessInfoString(int pid, boolean showName) {
    	
    	ProcessInfoTable.ProcessInfo pi = mProcTable.get(pid);    	
    	
    	int[] pids = new int[1];
    	pids[0] = pid;
    	Debug.MemoryInfo[] info = mActivityManager.getProcessMemoryInfo(pids);
    	
    	int priv = info[0].getTotalPrivateDirty();
    	int shrd = info[0].getTotalSharedDirty();
    	int pss = info[0].getTotalPss();

    	String s = "";
    	
    	if (showName)
    		s += pi.name + "\n";
    	
    	s += "ID: " + pi.pkgName + "\n\n";
    	
    	s += String.format("MemPriv:\t%d.%03d Mb\n", priv / 1024, priv % 1024);
    	s += String.format("MemShrd:\t%d.%03d Mb\n", shrd / 1024, shrd % 1024); 
    	s += String.format("MemPss: \t%d.%03d Mb\n\n", pss / 1024, pss % 1024);
    	
    	for (String svc : pi.services) {
    		s += "S: " + svc + "\n";
    	}
    	
    	s += "\n" + getProcProcfsStatus(pid);

    	return s;
    }
    
    public String getProcessInfoString(int pid) {
    	return getProcessInfoString(pid, true);
    }
    
    // Kill process
    public boolean killProcess(int pid) {
    	if(pid <= 0) {
    		return false;
    	}
    	if(pid == android.os.Process.myPid()) {
    		android.os.Process.killProcess(pid);
    		return true;
    	}
    	
    	String packageName = mProcTable.getProcessPkgName(pid);
    	
    	if(packageName == null) {
			android.os.Process.killProcess(pid);
			return true;
    	}
    	Log.v(TAG, "killProcess [" + pid + "] " + packageName);
    	
		// This method is deprecated.
    	// For android2.2(API Level8), use ActivityManager.killBackgroundProcesses(String).
    	// ActivityManager.restartPackage(mProcessList.get(mKillProcessIndex).processName);
    	
    	Method method = null;
    	try {
    		method = mActivityManager.getClass().getMethod("killBackgroundProcesses", new Class[]{String.class});
    		//Toast.makeText(getApplicationContext(), "<invoke killBackgroundProcesses>", Toast.LENGTH_SHORT).show();
    		
    	} catch(NoSuchMethodException e) {
    		try {
    			method = mActivityManager.getClass().getMethod("restartPackage", new Class[]{String.class});
    		} catch(NoSuchMethodException ee) {
    			ee.printStackTrace();
    		}
    	}
    	if(method != null) {
    		try {
    			method.invoke(mActivityManager, packageName);
    		} catch(InvocationTargetException e) {
    			e.printStackTrace();
    		} catch(IllegalAccessException e) {
    			e.printStackTrace();
    		}
    	}
    	return true;
    }
    
    
    private List<String> byteToStrArray(byte[] b) {
		List<String> strList = new ArrayList<String>(1);
		int bLen = b.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream(bLen);
		try {
			for(int i = 0; i < bLen; i++) {
				if(i != 0 && b[i - 1] == 0 && b[i] == 0) {
					continue;
				}
				if(b[i] != '\n') {
					out.write(b[i]);
				} else {
					strList.add(new String(out.toByteArray()));
					out.reset();
				}
				if(b[i] == '\n' && i == bLen - 1) {
					strList.add(new String(out.toByteArray()));
				}
			}
			out.close();
		} catch(IOException e) {
			Log.e("TAG", "IOException", e);
		}
		return strList;
	}
    
	protected int getSysMemTotal() {
		//MemTotal:      1945312 kB
		File fMemInfo = new File("/proc/meminfo");
		if(fMemInfo == null || !fMemInfo.isFile() || !fMemInfo.canRead()) {
			return 0;
		}
		List<String> meminfo = null;
		if(fMemInfo != null && fMemInfo.isFile() && fMemInfo.canRead()) {
			try {
				byte[] buf = new byte[1024];
				FileInputStream fIn = new FileInputStream(fMemInfo);
				if(fIn.read(buf) != -1) {
					meminfo = byteToStrArray(buf);
				}
				fIn.close();
			} catch(FileNotFoundException e) {
				Log.e("TAG", "FileNotFoundException", e);
			} catch(IOException e) {
				Log.e("TAG", "IOException", e);
			}			
		}
		
		try {
			String str = meminfo.get(0);
			String str2 = str.substring(10, str.indexOf(" kB"));				
			String str3 = str2.substring(str2.lastIndexOf(" ")+1);
			Integer ret = Integer.parseInt(str3);
			return ret.intValue();
		} 
		catch (Exception ex) {
			return 0;
		}
	}
}
